
#include <assert.h>
#include <time.h>
#include "sdlJeu.h"
#include <SDL/SDL.h>


const int TAILLE_SPRITE=32;

SDL_Surface *SDL_load_image(const char* filename );
void SDL_apply_surface( SDL_Surface* source, SDL_Surface* destination, int x, int y );




/**
 * \fn void sdljeuInit(sdlJeu *pSdlJeu)
 * \brief Initialise la version SDL du jeu
 * \param [in,out] pSdlJeu Jeu initialisé par sdljeuInit
 */

void sdljeuInit(sdlJeu *pSdlJeu)
{


	Jeu *pJeu;
	int dimx, dimy;

	pJeu = &(pSdlJeu->jeu);
	jeuInit(pJeu);

	assert(   SDL_Init( SDL_INIT_EVERYTHING )!= -1 );

	dimx = getDimX( jeuGetConstTerrainPtr(pJeu) );
	dimy = getDimY( jeuGetConstTerrainPtr(pJeu) );
	dimx = dimx * TAILLE_SPRITE;
	dimy = dimy * TAILLE_SPRITE;
	pSdlJeu->surface_ecran = SDL_SetVideoMode(   dimx, dimy, 32, SDL_SWSURFACE );
	assert( pSdlJeu->surface_ecran!=NULL);
	SDL_WM_SetCaption( "Snake v0.1", NULL );

	pSdlJeu->surface_snake1 = SDL_load_image("data/carrebleu.bmp");
	if (pSdlJeu->surface_snake1==NULL)
		pSdlJeu->surface_snake1 = SDL_load_image("../data/carrebleu.bmp");
	assert( pSdlJeu->surface_snake1!=NULL);

    pSdlJeu->surface_snake2 = SDL_load_image("data/carrerouge.bmp");
	if (pSdlJeu->surface_snake2==NULL)
		pSdlJeu->surface_snake2 = SDL_load_image("../carrerouge.bmp");
	assert( pSdlJeu->surface_snake2!=NULL);

	pSdlJeu->surface_mur = SDL_load_image("data/mur.bmp");
	if (pSdlJeu->surface_mur==NULL)
		pSdlJeu->surface_mur = SDL_load_image("../data/mur.bmp");
	assert( pSdlJeu->surface_mur!=NULL);

    pSdlJeu->surface_acc = SDL_load_image("data/accelerer.bmp");
	if (pSdlJeu->surface_acc==NULL)
		pSdlJeu->surface_acc = SDL_load_image("../data/accelerer.bmp");
	assert( pSdlJeu->surface_acc!=NULL);

	pSdlJeu->surface_freine = SDL_load_image("data/freiner.bmp");
	if (pSdlJeu->surface_freine==NULL)
		pSdlJeu->surface_freine = SDL_load_image("../data/freiner.bmp");
	assert( pSdlJeu->surface_freine!=NULL);

	pSdlJeu->surface_gomme = SDL_load_image("data/gomme.bmp");
	if (pSdlJeu->surface_gomme==NULL)
		pSdlJeu->surface_gomme = SDL_load_image("../data/gomme.bmp");
	assert( pSdlJeu->surface_gomme!=NULL);

    pSdlJeu->surface_1 = SDL_load_image("data/1.bmp");
	if (pSdlJeu->surface_1==NULL)
		pSdlJeu->surface_1 = SDL_load_image("../data/1.bmp");
	assert( pSdlJeu->surface_1!=NULL);

	pSdlJeu->surface_2 = SDL_load_image("data/2.bmp");
	if (pSdlJeu->surface_2==NULL)
		pSdlJeu->surface_2 = SDL_load_image("../data/2.bmp");
	assert( pSdlJeu->surface_2!=NULL);

	pSdlJeu->surface_3 = SDL_load_image("data/3.bmp");
	if (pSdlJeu->surface_3==NULL)
		pSdlJeu->surface_3 = SDL_load_image("../data/3.bmp");
	assert( pSdlJeu->surface_3!=NULL);

	pSdlJeu->surface_4 = SDL_load_image("data/4.bmp");
	if (pSdlJeu->surface_4==NULL)
		pSdlJeu->surface_4 = SDL_load_image("../data/4.bmp");
	assert( pSdlJeu->surface_4!=NULL);

	pSdlJeu->surface_5 = SDL_load_image("data/5.bmp");
	if (pSdlJeu->surface_5==NULL)
		pSdlJeu->surface_5 = SDL_load_image("../data/5.bmp");
	assert( pSdlJeu->surface_5!=NULL);

	pSdlJeu->surface_6 = SDL_load_image("data/6.bmp");
	if (pSdlJeu->surface_6==NULL)
		pSdlJeu->surface_6 = SDL_load_image("../data/6.bmp");
	assert( pSdlJeu->surface_6!=NULL);

	pSdlJeu->surface_7 = SDL_load_image("data/7.bmp");
	if (pSdlJeu->surface_7==NULL)
		pSdlJeu->surface_7 = SDL_load_image("../data/7.bmp");
	assert( pSdlJeu->surface_7!=NULL);

	pSdlJeu->surface_8 = SDL_load_image("data/8.bmp");
	if (pSdlJeu->surface_8==NULL)
		pSdlJeu->surface_8 = SDL_load_image("../data/8.bmp");
	assert( pSdlJeu->surface_8!=NULL);

	pSdlJeu->surface_9 = SDL_load_image("data/9.bmp");
	if (pSdlJeu->surface_9==NULL)
		pSdlJeu->surface_9 = SDL_load_image("../data/9.bmp");
	assert( pSdlJeu->surface_9!=NULL);

	pSdlJeu->surface_bleu_gagne = SDL_load_image("data/Joueur1.bmp");
	if (pSdlJeu->surface_bleu_gagne==NULL)
		pSdlJeu->surface_bleu_gagne = SDL_load_image("../data/Joueur1.bmp");
	assert( pSdlJeu->surface_bleu_gagne!=NULL);

	pSdlJeu->surface_rouge_gagne = SDL_load_image("data/Joueur2.bmp");
	if (pSdlJeu->surface_rouge_gagne==NULL)
		pSdlJeu->surface_rouge_gagne = SDL_load_image("../data/Joueur2.bmp");
	assert( pSdlJeu->surface_rouge_gagne!=NULL);


}





/**
 * \fn void sdljeuAffTerrain(sdlJeu *pSdlJeu)
 * \brief Affiche le terrain en SDL
 * \param [in,out] pSdlJeu sdlJeu pour afficher le terrain
 */

void sdljeuAffTerrain(sdlJeu *pSdlJeu)
{
	int x,y;
    const Jeu *pJeu = &(pSdlJeu->jeu);
	const Terrain *pTer = jeuGetConstTerrainPtr(pJeu);
    pSdlJeu->jeu.afficherTerrain = 0;

    SDL_FillRect( pSdlJeu->surface_ecran, &pSdlJeu->surface_ecran->clip_rect, SDL_MapRGB( pSdlJeu->surface_ecran->format, 0x00, 0x00, 0x00 ) );


	for (x=0;x<getDimX(pTer);++x)
		for (y=0;y<getDimY(pTer);++y)
			if (terrainGetXY(pTer,x,y)=='#')
				SDL_apply_surface(  pSdlJeu->surface_mur, pSdlJeu->surface_ecran, x*TAILLE_SPRITE, y*TAILLE_SPRITE);

}




/**
 * \fn void sdljeuAffSnake(sdlJeu *pSdlJeu)
 * \brief Affiche les snakes en SDL
 * \param [in,out] pSdlJeu sdlJeu pour afficher les snakes
 */

void sdljeuAffSnake(sdlJeu *pSdlJeu)
{
    const Jeu *pJeu = &(pSdlJeu->jeu);
	const Snake *pSnake1 = jeuGetConstSnake1Ptr(pJeu);
    const Snake *pSnake2 = jeuGetConstSnake2Ptr(pJeu);

    SDL_apply_surface(  pSdlJeu->surface_snake1, pSdlJeu->surface_ecran, snakeGetX(pSnake1)*TAILLE_SPRITE,  snakeGetY(pSnake1)*TAILLE_SPRITE );
	SDL_apply_surface(  pSdlJeu->surface_snake2, pSdlJeu->surface_ecran, snakeGetX(pSnake2)*TAILLE_SPRITE,  snakeGetY(pSnake2)*TAILLE_SPRITE );
}




/**
 * \fn void sdljeuAffBonus(sdlJeu *pSdlJeu)
 * \brief Affiche les bonus en SDL
 * \param [in,out] pSdlJeu sdlJeu pour afficher les bonus
 */

void sdljeuAffBonus(sdlJeu *pSdlJeu)
{
    Jeu *pJeu = &(pSdlJeu->jeu);
    Bonus *pBonus = jeuGetConstBonusPtr(pJeu);

    initBonus(pBonus);
    if(pBonus->typeBonus == 0)
    {
        SDL_apply_surface( pSdlJeu->surface_acc, pSdlJeu->surface_ecran, getBonusX(pBonus)*TAILLE_SPRITE, getBonusY(pBonus)*TAILLE_SPRITE);
    }
    else if(pBonus->typeBonus == 1)
    {
        SDL_apply_surface( pSdlJeu->surface_freine, pSdlJeu->surface_ecran, getBonusX(pBonus)*TAILLE_SPRITE, getBonusY(pBonus)*TAILLE_SPRITE);
    }
    else if(pBonus->typeBonus == 2)
    {
        SDL_apply_surface( pSdlJeu->surface_gomme, pSdlJeu->surface_ecran, getBonusX(pBonus)*TAILLE_SPRITE, getBonusY(pBonus)*TAILLE_SPRITE);
    }
}

void sdljeuAffScore(sdlJeu *pSdlJeu)
{
    if (pSdlJeu->jeu.score1 == 1)
    {
        SDL_apply_surface( pSdlJeu->surface_1, pSdlJeu->surface_ecran, 1450,200);
    }
    if (pSdlJeu->jeu.score1 == 2)
    {
        SDL_apply_surface( pSdlJeu->surface_2, pSdlJeu->surface_ecran, 1450,200);
    }
    if (pSdlJeu->jeu.score1 == 3)
    {
        SDL_apply_surface( pSdlJeu->surface_3, pSdlJeu->surface_ecran, 1450,200);
    }
    if (pSdlJeu->jeu.score1 == 4)
    {
        SDL_apply_surface( pSdlJeu->surface_4, pSdlJeu->surface_ecran, 1450,200);
    }
    if (pSdlJeu->jeu.score1 == 5)
    {
        SDL_apply_surface( pSdlJeu->surface_5, pSdlJeu->surface_ecran, 1450,200);
    }
    if (pSdlJeu->jeu.score1 == 6)
    {
        SDL_apply_surface( pSdlJeu->surface_6, pSdlJeu->surface_ecran, 1450,200);
    }
    if (pSdlJeu->jeu.score1 == 7)
    {
        SDL_apply_surface( pSdlJeu->surface_7, pSdlJeu->surface_ecran, 1450,200);
    }
    if (pSdlJeu->jeu.score1 == 8)
    {
        SDL_apply_surface( pSdlJeu->surface_8, pSdlJeu->surface_ecran, 1450, 200);
    }
    if (pSdlJeu->jeu.score1 == 9)
    {
        SDL_apply_surface( pSdlJeu->surface_9, pSdlJeu->surface_ecran, 1450,200);
    }

    if (pSdlJeu->jeu.score2 == 1)
    {
        SDL_apply_surface( pSdlJeu->surface_1, pSdlJeu->surface_ecran, 1450,650);
    }
    if (pSdlJeu->jeu.score2 == 2)
    {
        SDL_apply_surface( pSdlJeu->surface_2, pSdlJeu->surface_ecran, 1450,650);
    }
    if (pSdlJeu->jeu.score2 == 3)
    {
        SDL_apply_surface( pSdlJeu->surface_3, pSdlJeu->surface_ecran, 1450,650);
    }
    if (pSdlJeu->jeu.score2 == 4)
    {
        SDL_apply_surface( pSdlJeu->surface_4, pSdlJeu->surface_ecran, 1450,650);
    }
    if (pSdlJeu->jeu.score2 == 5)
    {
        SDL_apply_surface( pSdlJeu->surface_5, pSdlJeu->surface_ecran, 1450,650);
    }
    if (pSdlJeu->jeu.score2 == 6)
    {
        SDL_apply_surface( pSdlJeu->surface_6, pSdlJeu->surface_ecran, 1450,650);
    }
    if (pSdlJeu->jeu.score2 == 7)
    {
        SDL_apply_surface( pSdlJeu->surface_7, pSdlJeu->surface_ecran, 1450,650);
    }
    if (pSdlJeu->jeu.score2 == 8)
    {
        SDL_apply_surface( pSdlJeu->surface_8, pSdlJeu->surface_ecran, 1450,650);
    }
    if (pSdlJeu->jeu.score2 == 9)
    {
        SDL_apply_surface( pSdlJeu->surface_9, pSdlJeu->surface_ecran, 1450,650);
    }
}

void sdljeuAffResultat(sdlJeu *pSdlJeu)
{
    if (pSdlJeu->jeu.score1 == 10)
    {
        SDL_apply_surface( pSdlJeu->surface_bleu_gagne, pSdlJeu->surface_ecran, 450,400);
    }
    if(pSdlJeu->jeu.score2 == 10)
    {
        SDL_apply_surface( pSdlJeu->surface_rouge_gagne, pSdlJeu->surface_ecran, 450,400);
    }

}

/**
 * \fn void sdljeuBoucle(sdlJeu *pSdlJeu)
 * \brief Boucle du jeu effectué à chaque coup d'horloge
 * \param [in,out] pSdlJeu sdlJeu pour afficher le terrain
 */

void sdljeuBoucle(sdlJeu *pSdlJeu)
{
	SDL_Event event;
	int continue_boucle = 1;
	int compteur_bonus;

    /* Horloges (en secondes) */
    float horloge_courante, horloge_precedente;

    /* Intervalle de temps (en secondes) entre deux évolutions du jeu */
    /* Changer la valeur pour ralentir ou accélérer le déplacement des fantomes */
    float intervalle_horloge = 0.2f;
    int rafraichissement;

	sdljeuAffTerrain(pSdlJeu);
    sdljeuAffSnake(pSdlJeu);
	assert( SDL_Flip( pSdlJeu->surface_ecran )!=-1 );

    /* Récupère l'horloge actuelle et la convertit en secondes */
    /* clock() retourne le nombre de tops horloge depuis le lancement du programme */
    horloge_precedente = (float)clock()/(float)CLOCKS_PER_SEC;


	/* Tant que ce n'est pas la fin ... */
	while ( continue_boucle == 1 )
	{
	    rafraichissement = 0;


	     /* Récupère l'horloge actuelle et la convertit en secondes */
        horloge_courante = (float)clock()/(float)CLOCKS_PER_SEC;

        /* Si suffisamment de temps s'est écoulé depuis la dernière prise d'horloge */
        if (horloge_courante-horloge_precedente>=intervalle_horloge)
        {
                compteur_bonus ++;
                jeuEvolue(&(pSdlJeu->jeu));
                rafraichissement = 1;
				horloge_precedente = horloge_courante;
        }
        if (compteur_bonus==15)
        {
            sdljeuAffBonus(pSdlJeu);
            compteur_bonus=0;
        }
        if (pSdlJeu->jeu.afficherTerrain==1)
        {
            sdljeuAffTerrain(pSdlJeu);
            sdljeuAffSnake(pSdlJeu);
			SDL_Delay(1500);
        }

        sdljeuAffScore(pSdlJeu);

        if(pSdlJeu->jeu.score1 == 10 || pSdlJeu->jeu.score2 == 10)
        {
            sdljeuAffResultat(pSdlJeu);
            SDL_Flip(pSdlJeu->surface_ecran);
            SDL_Delay(15000);
            pSdlJeu->jeu.score1 = 0;
            pSdlJeu->jeu.score2 = 0;
            sdljeuAffTerrain(pSdlJeu);
            sdljeuAffSnake(pSdlJeu);
        }

		/* tant qu'il y a des evenements à traiter : cette boucle n'est pas bloquante */
		while ( SDL_PollEvent( &event ) )
		{
			/* Si l'utilisateur a cliqué sur la croix de fermeture */
			if ( event.type == SDL_QUIT)
				continue_boucle = 0;

			/* Si l'utilisateur a appuyé sur une touche */
			if ( event.type == SDL_KEYDOWN )
			{
				switch ( event.key.keysym.sym )
				{
				case SDLK_UP:
					jeuActionClavier( &(pSdlJeu->jeu), 'h');
					rafraichissement = 1;
					break;
				case SDLK_DOWN:
					jeuActionClavier( &(pSdlJeu->jeu), 'b');
					rafraichissement = 1;
					break;
				case SDLK_LEFT:
					jeuActionClavier( &(pSdlJeu->jeu), 'g');
					rafraichissement = 1;
					break;
				case SDLK_RIGHT:
					jeuActionClavier( &(pSdlJeu->jeu), 'd');
					rafraichissement = 1;
					break;
				case SDLK_z:
					jeuActionClavier( &(pSdlJeu->jeu), 'H');
					rafraichissement = 1;
					break;
				case SDLK_s:
					jeuActionClavier( &(pSdlJeu->jeu), 'B');
					rafraichissement = 1;
					break;
				case SDLK_q:
					jeuActionClavier( &(pSdlJeu->jeu), 'G');
					rafraichissement = 1;
					break;
				case SDLK_d:
					jeuActionClavier( &(pSdlJeu->jeu), 'D');
					rafraichissement = 1;
					break;
				default: break;
				}
            }
		}

        if (rafraichissement==1)
        {
            /* on affiche le jeu sur le buffer caché */
            sdljeuAffSnake(pSdlJeu);

            /* on permute les deux buffers (cette fonction ne doit se faire qu'une seule fois dans a boucle) */
            SDL_Flip( pSdlJeu->surface_ecran );

        }
	}
}




/**
 * \fn void sdljeuLibere(sdlJeu *pSdlJeu)
 * \brief Libère l'espace occupé par le sdlJeu
 * \param [in,out] pSdlJeu sdlJeu à libérer
 */

void sdljeuLibere( sdlJeu *pSdlJeu)
{
	SDL_FreeSurface( pSdlJeu->surface_snake1 );
	SDL_FreeSurface( pSdlJeu->surface_snake2 );
	SDL_FreeSurface( pSdlJeu->surface_mur );
	SDL_FreeSurface( pSdlJeu->surface_acc );
	SDL_FreeSurface( pSdlJeu->surface_freine );
	SDL_FreeSurface( pSdlJeu->surface_gomme );
    SDL_FreeSurface( pSdlJeu->surface_1);
    SDL_FreeSurface( pSdlJeu->surface_2);
    SDL_FreeSurface( pSdlJeu->surface_3);
    SDL_FreeSurface( pSdlJeu->surface_4);
    SDL_FreeSurface( pSdlJeu->surface_5);
    SDL_FreeSurface( pSdlJeu->surface_6);
    SDL_FreeSurface( pSdlJeu->surface_7);
    SDL_FreeSurface( pSdlJeu->surface_8);
    SDL_FreeSurface( pSdlJeu->surface_9);
    SDL_FreeSurface( pSdlJeu->surface_bleu_gagne);
    SDL_FreeSurface( pSdlJeu->surface_rouge_gagne);

	jeuLibere(&(pSdlJeu->jeu));

	SDL_Quit();

}



SDL_Surface *SDL_load_image(const char* filename )
{
	/* Temporary storage for the image that's loaded */
	SDL_Surface* loadedImage = NULL;

	/* The optimized image that will be used */
	SDL_Surface* optimizedImage = NULL;

	/* Load the image */
	loadedImage = SDL_LoadBMP( filename );

	/* If nothing went wrong in loading the image */
	if ( loadedImage != NULL )
	{
		/* Create an optimized image */
		optimizedImage = SDL_DisplayFormat( loadedImage );

		/* Free the old image */
		SDL_FreeSurface( loadedImage );
	}

	/* Return the optimized image */
	return optimizedImage;
}


void SDL_apply_surface( SDL_Surface* source, SDL_Surface* destination, int x, int y )
{
	/* Make a temporary rectangle to hold the offsets */
	SDL_Rect offset;

	/* Give the offsets to the rectangle */
	offset.x = x;
	offset.y = y;

	/* Blit the surface */
	SDL_BlitSurface( source, NULL, destination, &offset );
}
